from typing import List, Dict, Any
from fastapi import APIRouter, Depends, HTTPException, Path, Request, Query, Body
from sqlalchemy.orm import Session
from fastapi.responses import StreamingResponse
import json
import asyncio
from sse_starlette.sse import EventSourceResponse

from app.db.session import get_db
from app.schemas.mcp_tool import (
    MCPTool, MCPToolDetail, MCPToolCreate, MCPToolUpdate,
    MCPToolsByCategory, ToolRunRequest, ToolRunResponse,
    ToolParamsResponse
)
from app.services.mcp_tool import MCPToolService, MCPCategoryService
from app.services.mcp_client import McpClient
from app.core.config import settings
from app.core.logger import setup_logging

# 设置日志
logger = setup_logging()

router = APIRouter()


@router.get("/", response_model=List[MCPTool])
def get_tools(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    """
    获取所有工具
    """
    return MCPToolService.get_tools(db, skip=skip, limit=limit)


@router.get("/by-category", response_model=List[MCPToolsByCategory])
def get_tools_by_category(db: Session = Depends(get_db)):
    """
    按分类获取工具
    """
    categories = MCPCategoryService.get_categories(db)
    result = []
    
    for category in categories:
        tools = MCPToolService.get_tools_by_category(db, category.id)
        if tools:  # 只包含有工具的分类
            result.append(MCPToolsByCategory(category=category, tools=tools))
    
    return result


@router.get("/by-category/{category_id}", response_model=List[MCPTool])
def get_tools_in_category(category_id: int, db: Session = Depends(get_db)):
    """
    获取指定分类下的所有工具
    """
    # 确认分类存在
    MCPCategoryService.get_category(db, category_id)
    return MCPToolService.get_tools_by_category(db, category_id)


@router.get("/{tool_id}", response_model=MCPToolDetail)
def get_tool(tool_id: int, db: Session = Depends(get_db)):
    """
    获取指定ID的工具
    """
    return MCPToolService.get_tool(db, tool_id)


@router.get("/by-name/{english_name}", response_model=MCPToolDetail)
def get_tool_by_name(english_name: str, db: Session = Depends(get_db)):
    """
    根据英文名称获取工具
    """
    return MCPToolService.get_tool_by_english_name(db, english_name)


@router.post("/", response_model=MCPTool)
def create_tool(tool: MCPToolCreate, db: Session = Depends(get_db)):
    """
    创建新工具
    """
    return MCPToolService.create_tool(db, tool)


@router.put("/{tool_id}", response_model=MCPTool)
def update_tool(tool_id: int, tool: MCPToolUpdate, db: Session = Depends(get_db)):
    """
    更新工具
    """
    return MCPToolService.update_tool(db, tool_id, tool)


@router.delete("/{tool_id}")
def delete_tool(tool_id: int, db: Session = Depends(get_db)):
    """
    删除工具
    """
    MCPToolService.delete_tool(db, tool_id)
    return {"message": "工具已删除"}


@router.post("/{tool_id}/run", response_model=ToolRunResponse)
async def run_tool(tool_id: int, request: ToolRunRequest, db: Session = Depends(get_db)):
    """
    运行工具
    """
    logger.info(f"开始运行工具，工具ID: {tool_id}")
    logger.info(f"请求参数: {json.dumps(request.parameters, ensure_ascii=False)}")
    
    # 获取工具详情
    tool = MCPToolService.get_tool(db, tool_id)
    
    # 检查工具是否配置了MCP服务
    if tool.mcp_config:
        # 提取MCP服务URL
        server_url = McpClient.extract_server_url(tool.mcp_config)
        if server_url:
            logger.info(f"从MCP服务执行工具，服务URL: {server_url}")
            # 使用MCP客户端执行工具
            result = await McpClient.execute_tool(server_url, request.parameters)
            
            # 检查是否有错误
            if isinstance(result, dict) and "error" in result:
                logger.error(f"MCP执行出错: {result['error']}")
                # 如果MCP执行出错，返回错误信息
                return ToolRunResponse(
                    status="error",
                    error=result["error"]
                )
            
            logger.info(f"MCP执行成功，结果: {json.dumps(result, ensure_ascii=False)}")
            return ToolRunResponse(**result)
    
    # 如果没有配置MCP服务或执行失败，使用旧的方式执行
    logger.info("使用本地方式执行工具")
    result = MCPToolService.run_tool(db, tool_id, request.parameters)
    return ToolRunResponse(result=result["result"])


@router.get("/{tool_id}/params", response_model=ToolParamsResponse)
async def get_tool_params(tool_id: int, db: Session = Depends(get_db)):
    """
    从MCP获取工具参数
    """
    logger.info(f"开始获取工具参数，工具ID: {tool_id}")
    
    try:
        # 获取工具详情
        tool = MCPToolService.get_tool(db, tool_id)
        logger.info(f"获取到工具信息: {tool.name}, MCP配置: {json.dumps(tool.mcp_config, ensure_ascii=False) if tool.mcp_config else 'None'}")
        
        # 检查工具是否配置了MCP服务
        if not tool.mcp_config:
            logger.info("工具未配置MCP服务，返回本地参数")
            return ToolParamsResponse(parameters_schema=tool.parameters_schema or {})
        
        # 提取MCP服务URL
        server_url = McpClient.extract_server_url(tool.mcp_config)
        if not server_url:
            logger.warning("未找到MCP服务URL，返回本地参数")
            return ToolParamsResponse(parameters_schema=tool.parameters_schema or {})
        
        logger.info(f"开始从MCP服务获取参数，服务URL: {server_url}")
        # 使用MCP客户端获取参数
        params = await McpClient.get_tool_params(server_url)
        
        # 检查是否有错误
        if isinstance(params, dict) and "error" in params:
            logger.error(f"从MCP服务获取参数失败: {params['error']}")
            # 如果有错误，返回工具的参数并包含错误信息
            return ToolParamsResponse(
                parameters_schema=tool.parameters_schema or {},
                error=params["error"]
            )
        
        logger.info(f"成功从MCP服务获取参数: {json.dumps(params, ensure_ascii=False)}")
        # 正常返回获取到的参数
        return ToolParamsResponse(parameters_schema=params)
        
    except Exception as e:
        logger.error(f"获取工具参数失败: {str(e)}")
        logger.exception("详细错误栈:")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/tools")
async def list_tools():
    """获取工具列表"""
    try:
        client = McpClient()
        tools = await client.list_tools()
        return tools
    except Exception as e:
        logger.error(f"获取工具列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/tools/{tool_id}")
async def get_tool(tool_id: str):
    """获取工具详情"""
    try:
        client = McpClient()
        tools = await client.list_tools()
        tool = next((t for t in tools if t.get("id") == tool_id), None)
        if not tool:
            raise HTTPException(status_code=404, detail="工具不存在")
        return tool
    except Exception as e:
        logger.error(f"获取工具详情失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/tools/{tool_id}/run")
async def execute_tool(
    tool_id: str,
    params: Dict[str, Any] = Body(...)
):
    """执行工具"""
    async def event_generator():
        try:
            client = McpClient()
            tools = await client.list_tools()
            tool = next((t for t in tools if t.get("id") == tool_id), None)
            
            if not tool:
                yield {
                    "event": "error",
                    "data": "工具不存在"
                }
                return
                
            try:
                result = await client.execute_tool(tool_id, params)
                yield {
                    "event": "result",
                    "data": json.dumps(result)
                }
            except Exception as e:
                logger.error(f"执行工具失败: {str(e)}")
                yield {
                    "event": "error",
                    "data": str(e)
                }
            finally:
                yield {
                    "event": "complete",
                    "data": ""
                }
        except Exception as e:
            logger.error(f"处理工具执行请求失败: {str(e)}")
            yield {
                "event": "error",
                "data": str(e)
            }
            yield {
                "event": "complete",
                "data": ""
            }
    
    return EventSourceResponse(
        event_generator(),
        headers={
            "Content-Type": "text/event-stream",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no"
        }
    ) 